package com.torry.edss.domain.service.impl;

import com.torry.edss.application.cache.TradingDayCache;
import com.torry.edss.domain.accessor.*;
import com.torry.edss.domain.annotations.TacticBean;
import com.torry.edss.domain.enums.TacticMode;
import com.torry.edss.domain.model.Company;
import com.torry.edss.domain.model.HisDailyLine;
import com.torry.edss.domain.model.LimitUp;
import com.torry.edss.domain.service.TacticService;
import com.torry.edss.domain.valueobject.MarketPlate;
import com.torry.edss.infras.util.DateUtil;
import com.torry.edss.infras.util.NumberUtils;
import com.torry.edss.integration.dingtalk.DingTalkClient;
import com.torry.edss.integration.facade.RemoteApiFacade;
import com.torry.edss.integration.facade.enums.Direction;
import com.torry.edss.integration.facade.result.FetchDailyLineResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 首板涨停，次日低开收阴，没有跌破涨停板最低位。缩量
 */
@TacticBean(mode = TacticMode.BAOLIXIPAN_V3)
@Slf4j
public class BaoLiXiPanTacticServiceImplV3 implements TacticService {
    public static int allCount = 0;
    public static int profitCount = 0;
    @Resource
    private LimitUpAccessor limitUpAccessor;
    @Resource
    private CompanyAccessor companyAccessor;
    @Resource
    private HisDailyLineAccessor hisDailyLineAccessor;
    @Resource
    private LimitDownAccessor limitDownAccessor;
    @Resource
    private LimitBombAccessor limitBombAccessor;
    @Resource
    private RemoteApiFacade remoteApiFacade;
    @Resource
    private DingTalkClient dingTalkClient;

    @Override
    public boolean realTimePicking() {
        String date = DateUtil.formatDate(LocalDate.now());
//        if (result == null) return false;

        String limitDay = TradingDayCache.getLastTradingDay();
        List<LimitUp> limitUps = limitUpAccessor.findByDateAndContinuousCount(Collections.singletonList(limitDay), Collections.singletonList(1), null);

        Set<Long> companyIds = new HashSet<>();
        for (LimitUp limitUp : limitUps) {
            if (limitUp.getMarketValue() > 10000000000D) continue;
            Company company = companyAccessor.getById(limitUp.getCompanyId());
            if (company.getPlate() != MarketPlate.HSZB) {
                continue;
            }

            FetchDailyLineResult dayLine = remoteApiFacade.fetchCurrentDayLine(company.getCode());
            FetchDailyLineResult limitDayLine = remoteApiFacade.fetchDayLine(company.getCode(), limitDay, Direction.CURRENT);
            if (dayLine == null) continue;
            if (dayLine.getOpen().equals(dayLine.getHigh())) {
                continue;
            }
            if (dayLine.getLow().equals(dayLine.getPrice())) {
                continue;
            }
            FetchDailyLineResult previousDayLine = remoteApiFacade.fetchPreviousDayLine(company.getCode(), limitDay);
            if (limitBombAccessor.countByDateAndCompanyId(previousDayLine.getDate(), company.getId()) > 0) {
                continue;
            }
            if (limitDayLine.getVolume() / previousDayLine.getVolume() > 2) {
                continue;
            }
            if (limitDayLine.getVolume() / previousDayLine.getVolume() < 0.5) {
                continue;
            }
            if (dayLine.getVolume() > limitDayLine.getVolume() * 1.5) {
                continue;
            }
            if (dayLine.getHigh() > limitDayLine.getHigh()) {
                continue;
            }
            if (dayLine.getLow() < limitDayLine.getLow()) {
                continue;
            }
            if (dayLine.getOpen() <= dayLine.getPrice()) {
                continue;
            }
            companyIds.add(company.getId());
            log.info("{}, {}, {}", date, company.getCode(), company.getName());
        }

        if (CollectionUtils.isNotEmpty(companyIds)) {
            dingTalkClient.sendMsg(companyIds);
        }
        return true;
    }

    @Override
    public boolean hisPicking(String date) {
        if (!TradingDayCache.isTradingDay(date)) {
            return true;
        }
        String limitDay = TradingDayCache.getPreviousTradingDay(date);
        List<LimitUp> limitUps = limitUpAccessor
                .findByDateAndContinuousCount(Collections.singletonList(limitDay), Collections.singletonList(1), null);
        limitUps = limitUps.stream().filter(e -> e.getBombCount() > 0).collect(Collectors.toList());
        for (LimitUp limitUp : limitUps) {
            if (limitUp.getMarketValue() > 10000000000D) continue;
            Company company = companyAccessor.getById(limitUp.getCompanyId());
            if (company.getPlate() != MarketPlate.HSZB) continue;
            List<String> previousTradingDays = TradingDayCache.getPreviousTradingDays(limitDay, 6, false);
            int count = limitUpAccessor.countByDateAndCompanyId(previousTradingDays, company.getId());
            List<String> dates = TradingDayCache.getPreviousTradingDays(limitDay, 20, false);
            List<HisDailyLine> allDayLines1 = hisDailyLineAccessor.findAllDayLines(company.getCode(), dates);
            long count1 = allDayLines1.stream().filter(e -> e.getVolume() > limitUp.getQuantity()).count();
            if(count1 > 0) {
                continue;
            }
            if (count > 0) continue;
            HisDailyLine limitDayLine = hisDailyLineAccessor.getDayLine(company.getCode(), limitDay);
            HisDailyLine limitPreviousDayLine = hisDailyLineAccessor.getPreviousDayLine(company.getCode(), limitDay);
            HisDailyLine dayLine = hisDailyLineAccessor.getDayLine(company.getCode(), date);
            if (dayLine == null) continue;
            // 必须放量涨停
            if (limitDayLine.getVolume() < limitPreviousDayLine.getVolume()) continue;
            // 放量2倍以上涨停 也不行
            if (limitDayLine.getVolume() > limitPreviousDayLine.getVolume() * 2) continue;
            // 当日必须要有下影线，代表资金托底吃货
            if (dayLine.getLow().equals(dayLine.getClose())) continue;
            // 当日要缩量
            if (dayLine.getVolume() > limitDayLine.getVolume()) continue;
            // 当日要收真阴线
            if (dayLine.getOpen() <= dayLine.getClose() || dayLine.getUpPercentage() > 0) continue;
            // 不能超涨停板最高价，代表主力资金没有盈利
            if (dayLine.getHigh() > limitDayLine.getHigh()) continue;
            // 收盘跌破保护位
            if (dayLine.getClose() <= limitDayLine.getLow()) continue;

            if (TradingDayCache.getLastTradingDay().equals(date)) {
                log.info("{}, {}, {}", date, company.getCode(), company.getName());
            } else {
                List<HisDailyLine> allDayLines = hisDailyLineAccessor.findAllDayLines(company.getCode());
                int index = allDayLines.stream().map(e -> DateUtil.formatDate(e.getDate())).collect(Collectors.toList()).indexOf(date);

                double maxPrice = allDayLines.get(index).getClose();
                double minPrice = allDayLines.get(index).getClose();
                for (int i = index + 1; i <= index + 1; i++) {
                    if (i == allDayLines.size()) {
                        break;
                    }
                    HisDailyLine dailyLine = allDayLines.get(i);
                    if (dailyLine.getHigh() > maxPrice) {
                        maxPrice = dailyLine.getHigh();
                    }
                    if (dailyLine.getLow() < minPrice) {
                        minPrice = dailyLine.getLow();
                    }
                }

                double profit = NumberUtils.format((maxPrice - allDayLines.get(index).getClose()) / allDayLines.get(index).getClose() * 100);
                double loss = NumberUtils.format((allDayLines.get(index).getClose() - minPrice) / allDayLines.get(index).getClose() * 100);
                allCount++;

                String msg = date + ", " + company.getCode() + ", " + company.getName() + ", 次日盈利: " + profit + " %, 次日亏损: " + loss + "%, 涨停量倍: "
                        + NumberUtils.format(limitDayLine.getVolume() / limitPreviousDayLine.getVolume()) +
                        ", 首阴量倍: " + NumberUtils.format(dayLine.getVolume() / limitDayLine.getVolume()) + ", 统计: " + limitUp.getStat()
                        + "， 市值： " + (limitUp.getMarketValue() / 100000000) + "亿，炸板次数: " + limitUp.getBombCount();

                if (profit > 5) {
                    profitCount++;
                    System.err.println(msg);
                } else {
                    System.out.println(msg);
                }
            }
        }
        return true;
    }

    @Override
    public boolean refreshProfit(Integer limit) {
        return false;
    }
}
